import React, { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import {
  Space,
  Card,
  Empty,
  Button,
  DatePicker,
  Descriptions,
  Form,
  InputNumber,
  Select,
  Switch,
  Popover,
  Table,
  Typography,
  Spin,
  Modal,
  message
} from 'antd';
import type { DescriptionsProps } from 'antd';
import {
  ArrowLeftOutlined,
  DeleteOutlined,
  EnterOutlined,
  ExclamationCircleFilled,
  LockOutlined,
  ThunderboltOutlined
} from '@ant-design/icons';
import columns from '../../components/columns/taskDetailColumns';
import { useStore, observer } from '../../store/task/storeHook';
import { getDateText } from '../../utils/dateUtil';
import {
  appTypes,
  booleanOptions,
  executeStatuses,
  taskFrequencies,
  getOptionLabel
} from '../../data/statusData';

const { RangePicker } = DatePicker;

const { Paragraph } = Typography;

const TaskDetail: React.FC = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const [messageApi, contextHolder] = message.useMessage();
  const [modal, modalContextHolder] = Modal.useModal();
  const [searchForm] = Form.useForm();
  const store: any = useStore();

  const [isLogModalOpen, setIsLogModalOpen] = useState<boolean>(false);
  const [logs, setLogs] = useState<string[]>([]);
  const [errorCount, setErrorCount] = useState<number>(0);
  const [errorIndex, setErrorIndex] = useState<number>(1);
  const [active, setActive] = useState<boolean>(false);
  const taskData = store.task.record?.task || {};
  const userData = store.task.record?.user || {};
  const sourceCompany = store.task.record?.sourceCompany || {};
  const targetCompany = store.task.record?.targetCompany || {};

  const pagination = {
    showSizeChanger: true,
    showQuickJumper: true,
    pageSizeOptions: [10, 20, 30, 40, 50, 100],
    current: store.task.taskDetailCurrent + 1,
    pageSize: store.task.taskDetailPageSize,
    total: store.task.taskDetailTotal,
    onChange: (page: number, pageSize: number) => {
      store.task.setTaskDetailPageSize(pageSize);
      search(page - 1);
    },
    onShowSizeChange: (current: number, size: number) => {
      store.task.setTaskDetailPageSize(size);
      search(current - 1);
    }
  };

  const fetchDetail = () => {
    const taskId: string = location.pathname.split('/').pop() || '';
    store.task.fetchDetail(taskId, (data: any) => setActive(data.task?.active || false));
  };

  const search = (page: number) => {
    const values = searchForm.getFieldsValue(true);
    const dateRange = values.dateRange;
    let startDate = getDateText(dateRange ? dateRange[0] : null);
    let endDate = getDateText(dateRange ?dateRange[1] : null);
    store.task.fetchTaskDetails(startDate, endDate, values.executeStatus, values.reverseOrder, page);
  };

  const updateTask = async (field: string, value: any) => {
    const res: any = await store.task.updateData(field, value);
    const data = res.data || null;
    if (data) {
      store.task.setRecord(data);
      setActive(data.task?.active);
      messageApi.success('更新成功');
    } else {
      messageApi.error(res.message || '更新失败');
    }
  }

  const deleteTask = () => {
    modal.confirm({
      title: '确定删除当前任务？',
      icon: <ExclamationCircleFilled />,
      onOk() {
        store.task.deleteData().then((res: any) => {
          if (res.success) {
            messageApi.info('删除成功');
            navigate('/task_list');
          } else {
            messageApi.error(res.message);
          }
        });
      },
      onCancel() {}
    });
  };

  const showTaskDetailLog = (record: any) => {
    const log: string = (record.log || '').trim();
    const logs: string[] = log ? log.split('\r\n\r\n') : [];
    let count: number = 0;
    logs.forEach(text => text.substring(20, 27) === '[ERROR]' && count++);
    setLogs(logs);
    setErrorCount(count);
    setErrorIndex(1);
    setIsLogModalOpen(true);
  };

  const getDayText = (taskData: any) => {
    let text: string = '';
    if (taskData.frequency === 'Monthly') {
      text = taskData.dayOfMonth > 0 ? ('每月第' + taskData.dayOfMonth + '天') : ('每月倒数第' + Math.abs(taskData.dayOfMonth) + '天');
    } else if (taskData.frequency === 'Weekly') {
      text = '每周' + '日一二三四五六'.charAt(taskData.dayOfWeek);
    } else {
      text = '-';
    }
    return text;
  };

  const getTimeText = (taskData: any) => {
    const hour = (taskData.hour >= 10 ? '' : '0') + taskData.hour;
    const minute = (taskData.minute >= 10 ? '' : '0') + taskData.minute;
    return hour + ':' + minute;
  };

  const splitLog = (log: string) => {
    const result: { type: 'title' | 'text' | 'code'; content: string; error?: boolean }[] = [];
    result.push({
      type: 'title',
      content: log.substring(0, log.indexOf('] ') + 2),
      error: log.substring(0, log.indexOf('] ')).endsWith('ERROR')
    });
    const text: string = log.substring(log.indexOf('] ') + 2);
    const regex = /\[code\]([\s\S]*?)\[\/code\]/g;
    let lastIndex = 0;
    let match: RegExpExecArray | null;
    while ((match = regex.exec(text)) !== null) {
      if (match.index > lastIndex) {
        result.push({
          type: 'text',
          content: text.substring(lastIndex, match.index)
        });
      }
      result.push({
        type: 'code',
        content: match[1]
      });
      lastIndex = regex.lastIndex;
    }
    if (lastIndex < text.length) {
      result.push({
        type: 'text',
        content: text.substring(lastIndex)
      });
    }
    return result;
  };

  const scrollToErrorLog = () => {
    const logs: NodeListOf<Element> = document.querySelectorAll('.log-container .log.error');
    logs[errorIndex - 1]?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(() => {
    fetchDetail();
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  const items: DescriptionsProps['items'] = [
    {
      key: 'title',
      label: '标题',
      span: { xs: 1, sm: 1, md: 1, lg: 1, xl: 2 },
      children: (
        <div style={{
          display: 'flex',
          gap: 16
        }}>
          <Paragraph
            editable={{
              maxLength: 128,
              onChange: (value: string) => updateTask('title', value)
            }}
            className="descriptions-paragraph"
          >
            {taskData.title}
          </Paragraph>
          <Switch
            checked={active}
            checkedChildren="启用"
            unCheckedChildren="停用"
            onChange={(checked: boolean) => {
              setActive(checked);
              updateTask('active', checked);
            }}
          />
        </div>
      )
    },
    {
      key: 'user',
      label: '用户',
      children: userData.username
    },
    {
      key: 'sourceCompanyId',
      label: '来源公司',
      children: sourceCompany.name
    },
    {
      key: 'sourceAppType',
      label: '来源应用类型',
      children: getOptionLabel(appTypes, taskData.sourceAppType)
    },
    {
      key: 'sourceDepartmentName',
      label: '来源部门',
      children: taskData.sourceDepartmentName
    },
    {
      key: 'targetCompanyId',
      label: '目标公司',
      children: targetCompany.name
    },
    {
      key: 'targetAppType',
      label: '目标应用类型',
      children: (
        taskData.targetAppType === 'Netease' ? (
          <Space size={8}>
            { getOptionLabel(appTypes, taskData.targetAppType) }
            <Popover
              content={taskData.defaultPassword || 'Abc-1234'}
              title="创建账号默认密码"
              trigger="hover"
            >
              <LockOutlined
                style={{
                  color: 'rgba(0, 0, 0, 0.45)',
                  cursor: 'pointer'
                }}
              />
            </Popover>
          </Space>
        ) : getOptionLabel(appTypes, taskData.targetAppType)
      )
    },
    {
      key: 'targetDepartmentName',
      label: '目标部门',
      children: taskData.targetDepartmentName
    },
    {
      key: 'includingChildren',
      label: '包含子部门',
      children: getOptionLabel(booleanOptions, (taskData.includingChildren || 'false').toString())
    },
    {
      key: 'includingEmployees',
      label: '包含雇员',
      children: getOptionLabel(booleanOptions, (taskData.includingEmployees || 'false').toString())
    },
    {
      key: 'deleteNonExistentChildren',
      label: '删除不存在的子部门',
      children: getOptionLabel(booleanOptions, (taskData.deleteNonExistentChildren || 'false').toString())
    },
    {
      key: 'frequency',
      label: '同步频率',
      children: getOptionLabel(taskFrequencies, taskData.frequency)
    },
    {
      key: 'dayOfWeek',
      label: '执行天',
      children: getDayText(taskData)
    },
    {
      key: 'hour_minute',
      label: '执行时间',
      children: getTimeText(taskData)
    },
    {
      key: 'maxRetryCount',
      label: '最大重试次数',
      children: taskData.maxRetryCount || '-'
    },
    {
      key: 'retryInterval',
      label: '重试间隔时间',
      children: taskData.retryInterval ? (taskData.retryInterval + '分钟') : '-'
    },
    {
      key: 'createdAt',
      label: '任务创建时间',
      children: taskData.createdAt
    },
    {
      key: 'id',
      label: '',
      span: 'filled',
      children: ''
    },
    {
      key: 'successBatchCount',
      label: '成功执行批次数',
      children: `${taskData.successBatchCount} / ${taskData.batchCount}`
    },
    {
      key: 'lastExecuteStatus',
      label: '最近任务执行状态',
      children: getOptionLabel(executeStatuses, taskData.lastExecuteStatus)
    },
    {
      key: 'lastRetryCount',
      label: '最近任务重试次数',
      children: taskData.lastRetryCount
    },
    {
      key: 'lastPlanTime',
      label: '最近任务计划时间',
      children: taskData.lastPlanTime ? taskData.lastPlanTime.substr(0, 10) : ''
    },
    {
      key: 'lastStartTime',
      label: '最近任务开始时间',
      children: taskData.lastStartTime
    },
    {
      key: 'lastEndTime',
      label: '最近任务结束时间',
      children: taskData.lastEndTime
    }
  ];

  return (
    <Spin
      size="large"
      spinning={false}
    >
      {contextHolder}
      {modalContextHolder}
      <Space
        direction="vertical"
        size={[0, 16]}
        style={{ width: '100%', padding: 16 }}
      >
        <Card
          title="任务详情"
          extra={
            <Button
              size="small"
              type="link"
              style={{ padding: 0}}
              onClick={() => navigate(-1)}
            >
              <ArrowLeftOutlined />
              返回
            </Button>
          }
        >
          <Space style={{ marginBottom: 16 }}>
            <Button
              type="primary"
              icon={<ThunderboltOutlined />}
              onClick={() => fetchDetail()}
            >
              刷新
            </Button>
            <Button
              danger
              icon={<DeleteOutlined />}
              onClick={() => deleteTask()}
            >
              删除
            </Button>
          </Space>
          <Descriptions
            bordered
            column={{ xs: 1, sm: 1, md: 1, lg: 1, xl: 3 }}
            items={items}
            className="task-detail-descriptions"
          />
        </Card>
        <Card title="任务明细">
          <Form
            form={searchForm}
            name="searchForm"
            autoComplete="off"
            colon={false}
            layout="inline"
            initialValues={{
              dateRange: null,
              executeStatus: '',
              reverseOrder: true
            }}
            className="search-form"
            style={{
              marginBottom: 16,
              padding: 0
            }}
          >
            <Form.Item
              name="dateRange"
              label="计划时间"
            >
              <RangePicker
                allowEmpty={[true, true]}
                format="YYYY-MM-DD"
                showTime={false}
                placeholder={['开始时间', '结束时间']}
              />
            </Form.Item>
            <Form.Item
              name="executeStatus"
              label="任务执行状态"
            >
              <Select
                options={executeStatuses}
                style={{ width: 100 }}
              />
            </Form.Item>
            <Form.Item
              name="reverseOrder"
              label="排序"
            >
              <Select
                style={{ width: 120 }}
                options={[
                  { value: false, label: '正序' },
                  { value: true, label: '倒序' }
                ]}
              />
            </Form.Item>
            <Form.Item>
              <Button
                type="primary"
                onClick={() => search(0)}
              >
                查询
              </Button>
            </Form.Item>
          </Form>
          <Table
            columns={columns(showTaskDetailLog, executeStatuses)}
            dataSource={store.task.taskDetails}
            rowKey={record => record.id}
            loading={store.task.taskDetailLoading}
            bordered
            scroll={{ x: 'max-content' }}
            pagination={pagination}
          />
        </Card>

        <Modal
          title="任务执行日志"
          open={isLogModalOpen}
          maskClosable={false}
          destroyOnHidden
          forceRender
          width={960}
          style={{ minWidth: 320 }}
          onCancel={() => setIsLogModalOpen(false)}
          footer={null}
        >
          <Space
            direction="vertical"
            size={12}
            style={{ width: '100%' }}
          >
            {
              errorCount > 0 ? (
                <InputNumber
                  addonBefore={`定位到错误日志 (共${errorCount}个)`}
                  addonAfter={
                    <Button
                      type="link"
                      style={{
                        height: 30,
                        margin: '0 -11px'
                      }}
                      onClick={() => scrollToErrorLog()}
                    >
                      <EnterOutlined />
                    </Button>
                  }
                  formatter={(value) => `第 ${value} 个`}
                  value={errorIndex}
                  min={1}
                  max={errorCount}
                  style={{
                    width: 340
                  }}
                  onChange={value => setErrorIndex(value as number)}
                  onPressEnter={() => scrollToErrorLog()}
                />
              ) : null
            }
            <div
              className="log-container"
              style={{
                border: '1px solid #f0f0f0',
                borderRadius: 8,
                maxHeight: 480,
                overflowY: 'auto',
                padding: 12
              }}
            >
              {
                (logs && logs.length > 0) ? (
                  logs.map((log: string, index: number) => {
                    const texts: any[] = splitLog(log);
                    return (
                      <Paragraph
                        key={index}
                        className={`log${texts[0].error ? ' error' : ''}`}
                      >
                        {
                          texts.map((text: any, index: number) => (
                            <Typography.Text
                              key={index}
                              strong={text.type === 'title' ? true : undefined}
                              type={texts[0].error ? 'danger': undefined}
                            >
                              {
                                text.type === 'code' ? (
                                  <pre style={{
                                    backgroundColor: 'transparent',
                                    borderRadius: 0,
                                    borderStyle: 'none',
                                    color: 'rgba(0, 0, 0, 0.45)',
                                    fontSize: '0.8rem',
                                    margin: 0
                                  }}>
                                    {text.content}
                                  </pre>
                                ) : text.content
                              }
                            </Typography.Text>
                          ))
                        }
                      </Paragraph>
                    );
                  })
                ) : (
                  <Empty
                    description="暂无日志"
                    style={{ margin: 16 }}
                  />
                )
              }
            </div>
          </Space>
        </Modal>
      </Space>
    </Spin>
  );
};

export default observer(TaskDetail);
